// 播放音频
package audio

import (
	"bytes"
	"io"
	"os"
	"time"

	"github.com/hajimehoshi/ebiten/v2/audio"
	"github.com/hajimehoshi/ebiten/v2/audio/mp3"
	"github.com/hajimehoshi/ebiten/v2/audio/vorbis"
	"github.com/hajimehoshi/ebiten/v2/audio/wav"
)

type musicType int

const (
	sampleRate          = 48000 //采样率
	introLengthInSecond = 0
	loopLengthInSecond  = 1
)

const (
	TypeOgg musicType = iota
	TypeMP3
	TypeWav
)

type audio_player struct {
	player *audio.Player
}

// path 播放src
// mtype 编码类型
// loop 循环吗
func NewPlayerFromFile(path string, mtype musicType, loop bool) (*audio_player, error) {
	buffer, e := os.ReadFile(path)
	if e != nil {
		return nil, e
	}

	return NewPlayerFromReader(bytes.NewReader(buffer), mtype, loop)
}

func NewPlayerFromReader(reader io.Reader, mtype musicType, loop bool) (*audio_player, error) {
	ctx := audio.NewContext(sampleRate)

	type audioStream interface {
		Read(p []byte) (int, error)
		Seek(offset int64, whence int) (int64, error)
		Length() int64
	}

	var s audioStream
	var e error
	switch mtype {
	case TypeMP3:
		s, e = mp3.Decode(ctx, reader)
		if e != nil {
			return nil, e
		}
	case TypeOgg:
		s, e = vorbis.Decode(ctx, reader)
		if e != nil {
			return nil, e
		}
	case TypeWav:
		s, e = wav.Decode(ctx, reader)
		if e != nil {
			return nil, e
		}
	}

	var p *audio.Player
	if loop {
		// 传入参数导言长度和循环长度，秒数是常量，*4的原因：16 bits 双通道 ··> 2 字节 * 2 通道
		s := audio.NewInfiniteLoopWithIntro(s, introLengthInSecond*4*sampleRate, loopLengthInSecond*4*sampleRate)
		p, e = ctx.NewPlayer(s)
	} else {
		p, e = ctx.NewPlayer(s)
	}

	if e != nil {
		return nil, e
	}

	return &audio_player{
		player: p,
	}, nil
}

// Play plays the stream.
func (this *audio_player) Play() {
	if !this.IsPlaying() {
		this.player.Play()
	}
}

// Pause pauses the playing.
func (this *audio_player) Pause() {
	if this.IsPlaying() {
		this.player.Pause()
	}
}

// Close closes the stream.
func (this *audio_player) Close() {
	if this.IsPlaying() {
		this.player.Close()
	}
}

// IsPlaying returns boolean indicating whether the player is playing.
func (this *audio_player) IsPlaying() bool {
	return this.player.IsPlaying()
}

// Volume returns the current volume of this player [0-1].
func (this *audio_player) Volume() float64 {
	return this.player.Volume()
}

// SetVolume sets the volume of this player.
// volume must be in between 0 and 1. SetVolume panics otherwise.
func (this *audio_player) SetVolume(volume float64) {
	if !(volume <= 1 && volume >= 0) {
		volume = 1
	}
	this.player.SetVolume(volume)
}

// Rewind rewinds the current position to the start.
func (this *audio_player) Rewind() error {
	return this.player.Rewind()
}

// Current returns the current position in time.
func (this *audio_player) Current() time.Duration {
	return this.player.Current()
}

// Seek seeks the position with the given offset.
func (this *audio_player) Seek(offset time.Duration) error {
	return this.player.Seek(offset)
}
